package me.buick.util.jmeter.snmpprocessvisualizers;

import java.io.Serializable;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import me.buick.util.jmeter.snmpprocess.snmpmgmt.SNMPProcessSampleResult;

import org.apache.jmeter.monitor.util.Stats;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.visualizers.MonitorListener;
import org.apache.jmeter.visualizers.MonitorModel;
import org.apache.jmeter.visualizers.MonitorStats;


public class SNMPProcessMonitorSNMPAccumModel implements Clearable, Serializable {
	
	List sampleList;
	String snmpSuiteName;

	/**
	 * we use this to set the current monitorModel so that we can save the stats
	 * to the resultcolllector.
	 */
	private MonitorModel CURRENT;

	private List listeners;

	/**
	 * By default, we set the default to 800
	 */
	private int DEFAULT_BUFFER = 800;

	/**
	 * 
	 */
	public SNMPProcessMonitorSNMPAccumModel(String snmpSuiteName) {
		sampleList = Collections.synchronizedList(new LinkedList());
		listeners = new LinkedList();
		this.snmpSuiteName = snmpSuiteName;
	}

	public int getBufferSize() {
		return DEFAULT_BUFFER;
	}

	public void setBufferSize(int buffer) {
		DEFAULT_BUFFER = buffer;
	}

	/**
	 * Added this method we that we can save the calculated stats.
	 * 
	 * @return current sample
	 */
	public MonitorModel getLastSample() {
		return this.CURRENT;
	}
	
	void setSNMPSuiteID(String snmpSuiteID){
		this.snmpSuiteName = snmpSuiteID;
	}

	/**
	 * Method will look up the server in the map. The MonitorModel will be added
	 * to an existing list, or a new one will be created.
	 * 
	 * @param model
	 */
	public void addSample(MonitorModel model) {
		this.CURRENT = model;
		updateArray(model, sampleList);
	}

	/**
	 * We want to keep only 240 entries for each server, so we handle the object
	 * array ourselves.
	 * 
	 * @param model
	 */
	private List updateArray(MonitorModel model, List list) {
		if (list.size() < DEFAULT_BUFFER) {
			list.add(model);
		} else {
			list.add(model);
			list.remove(0);
		}
		return list;
	}

	/**
	 * Get all MonitorModels matching the URL.
	 * 
	 * @param url
	 * @return list
	 */
	public List getAllSamples() {
		return sampleList;
	}

	/**
	 * Method will try to parse the response data. If the request was a monitor
	 * request, but the response was incomplete, bad or the server refused the
	 * connection, we will set the server's health to "dead". If the request was
	 * not a monitor sample, the method will ignore it.
	 * 
	 * @param sample
	 */
	public void addSample(SampleResult sample) {
		URL surl = null;
		if (sample instanceof SNMPProcessSampleResult) {
			SNMPProcessSampleResult sampleRs = (SNMPProcessSampleResult) sample;
			String suiteID = sampleRs.getSnmpSuiteID();
			if(suiteID != null && suiteID.trim().length() > 0){
				if(this.snmpSuiteName != null && this.snmpSuiteName.trim().equalsIgnoreCase(suiteID.trim())){
					surl = sampleRs.getURL();
		    		if (sampleRs.isResponseCodeOK()) {
		    			int cpuUsage = 1;
		    			if (surl != null && cpuUsage >= 0) {
		    				SNMPProcessMonitorModel mo = new SNMPProcessMonitorModel(sampleRs);
		    				this.addSample(mo);
		    				notifyListeners(mo);
		    			} else {
		    				noResponse(surl);
		    			}
		    		} else {
		    			noResponse(surl);
		    		}
				}else{
					return;
				}
			}else{
				surl = sampleRs.getURL();
	    		if (sampleRs.isResponseCodeOK()) {
	    			int cpuUsage = 1;
	    			if (surl != null && cpuUsage >= 0) {
	    				SNMPProcessMonitorModel mo = new SNMPProcessMonitorModel(sampleRs);
	    				this.addSample(mo);
	    				notifyListeners(mo);
	    			} else {
	    				noResponse(surl);
	    			}
	    		} else {
	    			noResponse(surl);
	    		}
			}
        }
	}

	/**
	 * If there is no response from the server, we create a new MonitorStats
	 * object with the current timestamp and health "dead".
	 * 
	 * @param url
	 */
	public void noResponse(URL url) {
		notifyListeners(createNewMonitorModel(url));
	}

	/**
	 * Method will return a new MonitorModel object with the given URL. This is
	 * used when the server fails to respond fully, or is dead.
	 * 
	 * @param url
	 * @return new MonitorModel
	 */
	public MonitorModel createNewMonitorModel(URL url) {
		MonitorStats stat = new MonitorStats(Stats.DEAD, 0, 0, 0, 0, url.getHost(), String.valueOf(url.getPort()), url
				.getProtocol(), System.currentTimeMillis());
		MonitorModel mo = new MonitorModel(stat);
		return mo;
	}

	/**
	 * Clears everything except the listener. Do not clear the listeners. If we
	 * clear listeners, subsequent "run" will not notify the gui of data
	 * changes.
	 */
	public void clearData() {
		sampleList.clear();
	}

	/**
	 * notify the listeners with the MonitorModel object.
	 * 
	 * @param model
	 */
	public void notifyListeners(MonitorModel model) {
		for (int idx = 0; idx < listeners.size(); idx++) {
			MonitorListener ml = (MonitorListener) listeners.get(idx);
			ml.addSample(model);
		}
	}

	/**
	 * Add a listener. When samples are added, the class will notify the
	 * listener of the change.
	 * 
	 * @param listener
	 */
	public void addListener(MonitorListener listener) {
		listeners.add(listener);
	}
}